﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;

namespace BindTryParseMVC.Controllers
{
    public class CustomModelBinderController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        // 下面是使用 AuthorEntityBinder 在一个 Action中
        [HttpGet("get/{author}")]
        public IActionResult Get([ModelBinder(Name ="Id")]Author author)
        {
            if (author == null)
            {
                return NotFound();
            }
            return Ok(author);
        }


    }

    public class Author
    {
        public int Id { get; set; }

        public string Name { get; set; }
        public string GitHub { get; set; }
        public string Twitter { get; set; }
        public string BlogUrl { get; set; }
    }


    public class AuthorEntityBinder : IModelBinder
    {
        private readonly AuthorContext _authorContext;

        public AuthorEntityBinder(AuthorContext authorContext)
        {
            _authorContext = authorContext;
        }
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
                throw new ArgumentNullException(nameof(bindingContext));
            
            var modelName = bindingContext.ModelName;

            // Try to fetch the value of the argument by name
            var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
            if (valueProviderResult == ValueProviderResult.None)
            {
                return Task.CompletedTask;
            }

            bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
            var value = valueProviderResult.FirstValue;

            // Check if the argument value is null or empty
            if (string.IsNullOrEmpty(value))
            {
                return Task.CompletedTask;
            }

            if(!int.TryParse(value, out _))
            {
                bindingContext.ModelState.TryAddModelError(modelName, "Author Id must by an int");
                return Task.CompletedTask;
            }

            // 模拟从数据库根据Id获取model
            var model = _authorContext.Author.Id;
            bindingContext.Result = ModelBindingResult.Success(model);
            return Task.CompletedTask;

        }
    }

    public class AuthorContext
    {
        public Author  Author { get; set; }
    }


    /// <summary>
    /// 使用下面的类可以省略在 Controller  action 中绑定model 不用添加 ModelBinder 特性了
    /// </summary>
    public class AuthorEntityBindProvider : IModelBinderProvider
    {
        public IModelBinder? GetBinder(ModelBinderProviderContext context)
        {
            if(context == null) throw new ArgumentNullException(nameof (context));

            if(context.Metadata.ModelType == typeof(Author))
            {
                return new BinderTypeModelBinder(typeof(AuthorEntityBinder));
            }
            return null;
        }
    }

}
